package fem2.analysis;

import fem2.Debugger;
import fem2.Model;
import fem2.enu.EchoLevelType;
import fem2.enu.MassMatrixType;
import fem2.enu.NewmarkType;
import fem2.strategies.CDMTimeIntegrationStrategy;
import fem2.strategies.ImplicitTimeIntegrationStrategy;
import fem2.strategies.NonAdaptiveNewmarkCrisfieldFormulationTimeIntegrationStrategy;
import fem2.strategies.NonAdaptiveNewmarkTimeIntegrationStrategy;

public class FreeVibrationAnalysis extends Analysis {

	private double alpha1;
	private double alpha2;
	private MassMatrixType massType;

	/**
	 * 
	 * @param m
	 * @param alpha1
	 *            Rayleigh damping coefficient for M
	 * @param alpha2
	 *            Rayleigh damping coefficient for K
	 */
	public FreeVibrationAnalysis(Model m, MassMatrixType massType, double alpha1, double alpha2) {
		super(m);
		this.alpha1 = alpha1;
		this.alpha2 = alpha2;
		this.massType = massType;
	}

	/**
	 * compute static solution of the model and update /**
	 * 
	 * @param m
	 *            model
	 * @param t0
	 *            initial time
	 * @param uHat
	 *            uHatGlobal container
	 */
	private final void computeInitialConditionAsStaticSolution(Model m, double t0, double[] uHat) {
		Analysis an = new LinearStaticAnalysis(m, t0);
		an.run();

		an.getModel().getMesh().copyUHatGlobal(uHat);

		if (getStrategy().getEchoLevel().contain(EchoLevelType.DEBUG)) {
			Debugger.watch("u0 = ", uHat);
		}
	}

	/**
	 * set analysis type to Generalized Newmark-alpha method
	 * 
	 * @param type
	 *            Newmark method
	 * @param rhoInf
	 *            rho-Infinity parameter
	 * @param t0
	 *            initial time
	 * @param stepping
	 *            time stepping
	 * @param nt
	 *            number of time steps
	 */
	public void setAnalysisTypeToNonAdaptiveNewmark(NewmarkType type, double rhoInf,
			final double t0, double stepping, int nt) {

		ImplicitTimeIntegrationStrategy s = new NonAdaptiveNewmarkTimeIntegrationStrategy(
				getModel(), massType, alpha1, alpha2, type, rhoInf, t0, stepping, nt) {

			@Override
			public void computeInitialCondition() {
				computeInitialConditionAsStaticSolution(getModel(), t0, this.uHat.getValues());
			}

		};

		setStrategy(s);
	}

	/**
	 * set analysis type to Generalized Newmark-alpha method using Crisfield
	 * formulation
	 * 
	 * @param type
	 *            Newmark method
	 * @param rhoInf
	 *            rho-Infinity parameter
	 * @param t0
	 *            initial time
	 * @param stepping
	 *            time stepping
	 * @param nt
	 *            number of time steps
	 */
	public void setAnalysisTypeToNonAdaptiveNewmarkCrisfieldFormulation(NewmarkType type,
			double rhoInf, final double t0, double stepping, int nt) {

		ImplicitTimeIntegrationStrategy s = new NonAdaptiveNewmarkCrisfieldFormulationTimeIntegrationStrategy(
				getModel(), massType, alpha1, alpha2, type, rhoInf, t0, stepping, nt) {

			@Override
			public void computeInitialCondition() {
				computeInitialConditionAsStaticSolution(getModel(), t0, this.uHat.getValues());
			}
		};

		setStrategy(s);
	}

	/**
	 * set analysis type to Central Differene method
	 * 
	 * @param t0
	 * @param stepping
	 * @param nt
	 */
	public void setAnalysisTypeToCDM(final double t0, double stepping, int nt) {

		ImplicitTimeIntegrationStrategy s = new CDMTimeIntegrationStrategy(getModel(), massType,
				alpha1, alpha2, t0, stepping, nt) {

			@Override
			public void computeInitialCondition() {
				computeInitialConditionAsStaticSolution(getModel(), t0, this.uHat.getValues());
			}
		};

		setStrategy(s);
	}
}
